﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Channels;
using System.Text;
using System.Threading.Tasks;

namespace ebMS3dotnet.Core
{
    sealed class ebMS3PackagingChannelListener<TShape> :
    ChannelListenerBase<TShape> where TShape : class, IChannel
    {
        private IChannelListener<TShape> _innerListener;

        public ebMS3PackagingChannelListener(BindingContext context)
        {
            _innerListener = context.BuildInnerChannelListener<TShape>();
        }
        protected override TShape OnAcceptChannel(TimeSpan timeout)
        {
            TShape innerChannel = _innerListener.AcceptChannel(timeout);
            if (innerChannel != null)
                return WrapChannel(innerChannel);

            return null;
        }

        protected override IAsyncResult OnBeginAcceptChannel(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return _innerListener.BeginAcceptChannel(timeout, callback, state);
        }

        protected override TShape OnEndAcceptChannel(IAsyncResult result)
        {
            TShape innerChannel = _innerListener.EndAcceptChannel(result);
            if (innerChannel != null)
                return WrapChannel(innerChannel);

            return null;
        }

        protected override IAsyncResult OnBeginWaitForChannel(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return _innerListener.BeginWaitForChannel(timeout, callback, state);
        }

        protected override bool OnEndWaitForChannel(IAsyncResult result)
        {
            return _innerListener.EndWaitForChannel(result);
        }

        protected override bool OnWaitForChannel(TimeSpan timeout)
        {
            return _innerListener.WaitForChannel(timeout);
        }

        public override Uri Uri
        {
            get { return _innerListener.Uri; }
        }

        protected override void OnAbort()
        {
            _innerListener.Abort();
        }

        protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return _innerListener.BeginClose(timeout, callback, state);
        }

        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return _innerListener.BeginOpen(timeout, callback, state);
        }

        protected override void OnClose(TimeSpan timeout)
        {
            _innerListener.Close(timeout);
        }

        protected override void OnEndClose(IAsyncResult result)
        {
            _innerListener.EndClose(result);
        }

        protected override void OnEndOpen(IAsyncResult result)
        {
            _innerListener.EndOpen(result);
        }

        protected override void OnOpen(TimeSpan timeout)
        {
            _innerListener.Open(timeout);
        }

        private TShape WrapChannel(TShape innerChannel)
        {
            if (innerChannel == null)
                throw new ArgumentNullException("innerChannel cannot be null", "innerChannel");

            if (typeof(TShape) == typeof(IReplyChannel))
                return (TShape)(object) (new ebMS3PackagingReplyChannel(this, (IReplyChannel)innerChannel));

            throw new ArgumentException("Invalid channel shape passed.");
        }
    }
}
